#!/usr/bin/python

# InnerSpace
# Copyright (C) 1999-2006 Phil Christensen
#
# $Id: verb.py 51 2006-10-16 05:20:29Z phil $
#
# See LICENSE for details

"""
Verb

Stability: barely stable

"""

from inner.space import code, parser, auth, security

class Verb:
	def __init__(self, code, names, owner, other_attribs):
		self.names = names
		self._vitals = {'acl':[], 'owner':owner, 'code':code, 
						'host_object':other_attribs['host_object']}
		if('is_ability' in other_attribs):
			self.is_ability = other_attribs['is_ability']
		else:
			self.is_ability = False
		
		if('is_method' in other_attribs):
			self.is_method = other_attribs['is_method']
		else:
			self.is_method = False
		
		if('acl_configure' in other_attribs):
			other_attribs['acl_configure'](self)
		else:
			security.default_verb_acl(self)
	
	def __getstate__(self):
		"""
		When this gets saved to disk, we get rid of
		the client reference.
		"""
		state = self.__dict__.copy()
		if(state['_vitals'].has_key('cache')):
			del state['_vitals']['cache']
		return state
	
	def __setstate__(self, state):
		"""
		See __getstate__
		"""
		for key in state.keys():
			self.__dict__[key] = state[key]
	
	def execute(self, env):
		security.check_allowed(auth.get_current_user(), "execute", self)
		"""
		We're going to modify the code here so that it's within a
		function definition. That way, verb code can use "return"
		to abort execution.
		"""
		if('cache' not in self._vitals):
			lines = self._vitals['code'].split("\n")
			final_code = "def ___verb_code___():\n"
			for line in lines:
				final_code += ("\t" + line + "\n")
			final_code += "\n__result__ = ___verb_code___()\n"
			self._vitals['cache'] = compile(final_code, str(self._vitals['host_object']) + ":" + self.names[0], 'exec')
		return code.r_exec(self._vitals['cache'], env)

	def call(self, source, args, kwargs):
		security.check_allowed(auth.get_current_user(), "execute", self)
		p = parser.Parser(parser.Lexer(""), auth.get_current_user(), auth.get_registry())
		env = code.get_environment(self, p)
		env['args'] = args
		env['kwargs'] = kwargs
		# note that we use 'source' instead of "self._vitals['host_object']"
		# here. i changed this awhile back, only to realize that 'this'
		# is generally thought to be the object where the verb was found
		# by the parser, not the one where the verb actually is defined
		env['this'] = source
		return self.execute(env)
		
	def get_owner(self):
		security.check_allowed(auth.get_current_user(), "read", self)
		return self._vitals['owner']
	
	def is_readable(self):
		return security.is_allowed(auth.get_current_user(), "read", self);
	
	def is_writeable(self):
		return security.is_allowed(auth.get_current_user(), "write", self);
	
	def is_executeable(self):
		return security.is_allowed(auth.get_current_user(), "execute", self);
	
	def get_code(self):
		security.check_allowed(auth.get_current_user(), "read", self);
		return self._vitals['code']